﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;
using Icst.Leaflike.Logging;

namespace Icst.Leaflike.Data
{
    public class Tree : DataContext<Tree>
    {
        protected static readonly string CACHE_ALL = "/Tree/All";
        protected static readonly string CACHE_ATTRS = "/Tree/Attrs";
        protected static readonly string CACHE_SEARCH = "/Tree/Search/";
        protected static HashSet<string> CACHE_ALL_SEARCH = new HashSet<string>();

        public tree TodayTree()
        {
            try
            {
                tree[] trees = CachePolicy.GetIf<tree[]>(CACHE_ALL, () => { return Context.trees.ToArray(); });
                if (trees.Length == 0)
                    return null;

                return trees[DateTime.Now.Day % trees.Length];
            }
            catch (Exception e)
            {
                Logger.Error("FAILED TO AllTrees. " + e.Message);
                return null;
            }
        }
        public tree_searchResult[] Search(string Shuxing, string Yexu, string Yexing, string Yeyuan,
            string Yejian, string Yeji, string Huaxing, string Guoshi, string Shupi, string Danfuye,
            string Guoshiyanse, string Huaqi, string Shugao, string Shuganyanse,
            int page, int pagesize, Func<tree_searchResult,bool> filter, out int totalCount)
        {
            tree_searchResult[] results = Search(Shuxing, Yexu, Yexing, Yeyuan, Yejian, Yeji, Huaxing,
                Guoshi, Shupi, Danfuye, Guoshiyanse, Huaqi, Shugao, Shuganyanse, filter);
            totalCount = results.Length;
            return results.Skip((page - 1) * pagesize).Take(pagesize).ToArray();
        }
        private tree_searchResult[] Search(string Shuxing, string Yexu, string Yexing, string Yeyuan,
            string Yejian, string Yeji, string Huaxing, string Guoshi, string Shupi, string Danfuye,
            string Guoshiyanse, string Huaqi, string Shugao, string Shuganyanse,Func<tree_searchResult,bool> filter)
        {
            try
            {
                string cachekey =
                    CACHE_SEARCH + Shuxing + Yexu + Yexing + Yeyuan + Yejian + Yeji + Huaxing + Guoshi + Shupi + Danfuye + Guoshiyanse + Huaqi + Shugao + Shuganyanse;
                if (!CACHE_ALL_SEARCH.Contains(cachekey))
                    CACHE_ALL_SEARCH.Add(cachekey);

                tree_searchResult[] results = CachePolicy.GetIf<tree_searchResult[]>(cachekey,
                    () =>
                    {
                        tree_searchResult[] sresults = Context.tree_search(Shuxing, Yexu, Yexing, Yeyuan, Yejian, Yeji, Huaxing,
            Guoshi, Shupi, Danfuye, Guoshiyanse, Huaqi, Shugao, Shuganyanse).ToArray();

                        Logger.Info("retrieve " + sresults.Length + " from database");

                        sresults = sresults.Where(p => filter(p)).ToArray();

                        Logger.Info("filtered to " + sresults.Length);

                        return sresults;
                    });

                return results;
            }
            catch (Exception e)
            {
                Logger.Error("FAILED TO SEARCH. " + e.Message);
                throw;
            }
        }
        public IEnumerable<tree_similarResult> SearchSimilar(int tree, int page, int pagesize, out int totalCount)
        {
            try
            {
                tree_similarResult[] results = Context.tree_similar(tree).ToArray();
                totalCount = results.Count();
                results = results.Skip((page - 1) * pagesize).Take(pagesize).ToArray();
                return results;
            }
            catch (Exception e)
            {
                Logger.Error("FAILED TO SEARCH SIMILAR, TREE=" + tree + ". " + e.Message);
                throw;
            }
        }
        public IEnumerable<tree_relevantResult> SearchRelevant(int tree, int page, int pagesize, out int totalCount)
        {
            try
            {
                tree_relevantResult[] results = Context.tree_relevant(tree).ToArray();
                totalCount = results.Count();
                results = results.Skip((page - 1) * pagesize).Take(pagesize).ToArray();
                return results;
            }
            catch (Exception e)
            {
                Logger.Error("FAILED TO SEARCH RELEVANT, TREE=" + tree + ". " + e.Message);
                throw;
            }
        }
        public tree_getinfoResult Getinfo(int tree)
        {
            try
            {
                return Context.tree_getinfo(tree).SingleOrDefault();
            }
            catch (Exception e)
            {
                Logger.Error("FAILED TO GET TREE INFO, TREE=" + tree + ". " + e.Message);
                throw;
            }
        }

        public static readonly string SHUXING = "01";
        public static readonly string YEXU = "02";
        public static readonly string YEXING = "03";
        public static readonly string YEYUAN = "04";
        public static readonly string YEJIAN = "05";
        public static readonly string YEJI = "06";
        public static readonly string HUAXING = "07";
        public static readonly string GUOSHI = "08";
        public static readonly string SHUPI = "09";
        public static readonly string GUOSHIYANSE = "10";
        public static readonly string DANFUYE = "11";
        public static readonly string SHUGANYANSE = "14";
        public static readonly string YEZI = "15";
        public tree_attr[] Attributes(string typeno, Version version)
        {
            switch (version)
            {
                case Version.Public: return AllAttrs.Where(p => p.type_no == typeno && p.pub == true).ToArray();
                case Version.Professional: return AllAttrs.Where(p => p.type_no == typeno && p.pro == true).ToArray();
                default: throw new Exception("unknown version");
            }
        }
        private tree_attr[] AllAttrs
        {
            get
            {
                try
                {
                    return CachePolicy.GetIf<tree_attr[]>(CACHE_ATTRS, () => { return Context.tree_attrs.ToArray(); });
                }
                catch (Exception e)
                {
                    Logger.Error("FAILED TO AllAttrs. " + e.Message);
                    throw;
                }
            }
        }

        public override void Refresh()
        {
            base.Refresh();

            Logger.Info("REFRESH CachePolicy.Clear");
            try { CachePolicy.Delete(CACHE_ALL); }
            catch { }
            try { CachePolicy.Delete(CACHE_ATTRS); }
            catch { }
            foreach (string key in CACHE_ALL_SEARCH)
            {
                try { CachePolicy.Delete(key); }
                catch { }
            }
        }
    }
}
